#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/errno.h>

#define GPMCON 0x7F008820
#define GPMDAT 0x7F008824

char *name = "first_dev";
static struct class *first_dev_class;

volatile unsigned long *gpmcon = NULL;
volatile unsigned long *gpmdat = NULL;

static int first_dev_open(struct inode *inode, struct file *file)
{
	printk("first_dev_open\n");

	//配置led灯为输出
	*gpmcon &= ~0xffff;
	*gpmcon |= 0x1111;

	return 0;	
}

static ssize_t first_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
	int val;

	printk("first_dev_write\n");

	while (1);

	if (copy_from_user(&val, buf, count))
	{
		return -EFAULT;
	}

	if (val == 0) {
		*gpmdat |= 0xf;
	} else {
		*gpmdat &= ~0xf;
	}

	return 0;
}

struct file_operations first_dev_fops = {
	.owner = THIS_MODULE,
	.open = first_dev_open,
	.write = first_dev_write,
};

int major;

static int __init first_dev_init(void) 
{
	major = register_chrdev(0, name, &first_dev_fops);

	first_dev_class = class_create(THIS_MODULE, name);
	device_create(first_dev_class, NULL, MKDEV(major, 0), &first_dev_init, "%s", name);	

	printk("%s_init and the device is %d\n", name, major);

	gpmcon = (volatile unsigned long *)ioremap(GPMCON, 16);
	gpmdat = gpmcon + 1;

	return 0;
}

static void __exit first_dev_exit(void)
{
	device_destroy(first_dev_class, MKDEV(major, 0));
	class_destroy(first_dev_class);
	unregister_chrdev(major, name);

	printk("%s_exit and device is %d\n", name, major);

	iounmap(gpmcon);
}

MODULE_LICENSE("GPL");
module_init(first_dev_init);
module_exit(first_dev_exit);
